const Clutter = imports.gi.Clutter;
const Gdk     = imports.gi.Gdk;
const GLib    = imports.gi.GLib;
const GtkClutter = imports.gi.GtkClutter;
const Gtk     = imports.gi.Gtk;
const Lang    = imports.lang;
const Mx      = imports.gi.Mx;
const Octopus = imports.gi.Octopus;
const Signals = imports.signals;

const AlbumArt = imports.albumArt;

const NamespaceEnum = {
	PLAYLIST: 0,
	COLLECTION: 1
}

function CollectionPanel(container) {
	this._init(container);
}

CollectionPanel.prototype = {
	_init: function (container) {
		this.collectionPanelStack = new Mx.Stack ({ name: 'collectionPanel-background',
		                                            reactive: true });
		container.add_child (this.collectionPanelStack);
		this.collectionPanelStack.connect('button-release-event', Lang.bind(this, this.onButtonReleaseEvent));

		this.collectionScrollView = new Mx.KineticScrollView ({ snap_on_page: false });
		this.collectionPanelStack.add_child (this.collectionScrollView);

		this.collectionLayout = new Mx.Grid ({ style_class: 'collectionPanel-layout',
		                                       orientation: Mx.Orientation.VERTICAL,
		                                       homogenous_rows: true,
		                                       homogenous_columns: true,
		                                       row_spacing: 0,
		                                       column_spacing: 0 });
		this.collectionScrollView.add_child (this.collectionLayout);

		this.collectionPanelSearchStack = new Mx.Stack ({ x_align: Clutter.ActorAlign.START,
		                                                  y_align: Clutter.ActorAlign.START,
		                                                  visible: false });
		this.collectionPanelStack.add_child (this.collectionPanelSearchStack);
		this.collectionPanelSearchGtkEntry = new Gtk.Entry ({ name: 'collectionPanel-search-entry',
		                                                      width_request: 200,
		                                                      height_request: 40,
		                                                      margin: 5 });
		this.collectionPanelSearchEntry = new GtkClutter.Actor ({ contents: this.collectionPanelSearchGtkEntry });
		this.collectionPanelSearchStack.add_child (this.collectionPanelSearchEntry);

		this.collectionPanelSearchCloseButton = new Mx.Button ({ style_class: 'collectionPanel-search-close',
		                                                         x_align: Clutter.ActorAlign.END,
		                                                         y_align: Clutter.ActorAlign.START,
		                                                         width: 20,
		                                                         height: 20 });
		this.collectionPanelSearchStack.add_child (this.collectionPanelSearchCloseButton);
		this.collectionPanelSearchCloseButton.connect ('clicked', Lang.bind(this, function () {
			this.collectionPanelSearchEntryClose ();
		}));
		this.timelineSearchClose = new Clutter.Timeline ({ duration: 3000 });
		this.timelineSearchClose.connect ('completed', Lang.bind(this, function () {
			if (this.collectionPanelSearchStack.visible) this.collectionPanelSearchEntryClose ();
		}));

		this.collectionPanelOverlay = new Mx.Frame ({ name: 'collectionPanel-overlay' });
		this.collectionPanelStack.add_child (this.collectionPanelOverlay);

		//create model
		this.collectionlist = new Octopus.Collectionlist ();
	},

	on_collection_add: function (/*IMedialibQuery*/collectionlist_model, /*IMedialibInfo*/collection_model) {
		let entry = new Collection (this.collectionLayout, -1, collection_model);
		collection_model.connect ('remove', Lang.bind (this, function (/**/ collection_model) {
			this.collectionLayout.remove_child (entry.collectionStack);
		}));
		entry.connect('collection-enter-event', Lang.bind(this, function (collection) {
			this.emit ('show-message-bar-text', collection_model.name);
		}));
		entry.connect('collection-leave-event', Lang.bind(this, function (collection) {
			this.emit ('show-message-bar-text', "");
		}));
		entry.connect('tracklist-panel-show', Lang.bind(this, function (collection) {
			this.emit ('tracklist-panel-show', collection_model);
		}));
	},

	on_collection_insert: function (/*IMedialibQuery*/collectionlist_model, /*IMedialibInfo*/collection_model, /*int*/pos) {
		pos++; //createPlaylist button
		pos++; //createCollection button
		let entry = new Collection (this.collectionLayout, pos, collection_model);
		collection_model.connect ('remove', Lang.bind (this, function (/**/ collection_model) {
			this.collectionLayout.remove_child (entry.collectionStack);
		}));
		entry.connect('collection-enter-event', Lang.bind(this, function (collection) {
			this.emit ('show-message-bar-text', collection_model.name);
		}));
		entry.connect('collection-leave-event', Lang.bind(this, function (collection) {
			this.emit ('show-message-bar-text', "");
		}));
		entry.connect('tracklist-panel-show', Lang.bind(this, function (collection) {
			this.emit ('tracklist-panel-show', collection_model);
		}));
	},

	onKeyPressEvent: function (/*uint*/keyval, /*string*/str, /*Gdk.ModifierType*/modifiers) {
		if (keyval == Gdk.KEY_Home) { //Home
			this.collectionLayout.horizontal_adjustment.value = 0;
		}
		if (keyval == Gdk.KEY_End) { //End
			this.collectionLayout.horizontal_adjustment.value = this.collectionLayout.horizontal_adjustment.upper;
		}
		if (keyval == Gdk.KEY_Page_Up) { //Page_Up
			this.collectionLayout.horizontal_adjustment.value =
			    this.collectionLayout.horizontal_adjustment.value
			  - this.collectionLayout.horizontal_adjustment.page_increment;
		}
		if (keyval == Gdk.KEY_Page_Down) { //Page_Down
			this.collectionLayout.horizontal_adjustment.value =
			    this.collectionLayout.horizontal_adjustment.value
			  + this.collectionLayout.horizontal_adjustment.page_increment;
		}
		if (   (keyval == Gdk.KEY_Up)
		    || (keyval == Gdk.KEY_Left)) { //Up, Left
			this.collectionLayout.horizontal_adjustment.value =
			    this.collectionLayout.horizontal_adjustment.value
			  - this.collectionLayout.horizontal_adjustment.step_increment;
		}
		if (   (keyval == Gdk.KEY_Down)
		    || (keyval == Gdk.KEY_Right)) { //Down, Right
			this.collectionLayout.horizontal_adjustment.value =
			    this.collectionLayout.horizontal_adjustment.value
			  + this.collectionLayout.horizontal_adjustment.step_increment;
		}

		//all printable characters
		if (   (GLib.unichar_isprint (str))
		    && (this.collectionPanelSearchStack.visible == false)) {
			this.notifyTextSignalId =
			this.collectionPanelSearchGtkEntry.connect ('notify::text', Lang.bind(this, function (/*Mx.Entry*/ entry) {
				//search_string_position returns -1 for no match
				let searchTextScrollPosition = this.collectionlist.search_string_position (this.collectionPanelSearchGtkEntry.text);
				if (searchTextScrollPosition >= 0) {
					searchTextScrollPosition++; //create Playlist
					searchTextScrollPosition++; //create Collection
					let collection_x = this.collectionLayout.get_child_at_index (searchTextScrollPosition).x;
					this.collectionLayout.horizontal_adjustment.value = collection_x - 100;
				}
				this.timelineSearchClose.stop ();
				this.timelineSearchClose.start ();
			}));
			this.collectionPanelSearchStack.visible = true;
			this.collectionPanelSearchGtkEntry.text = str;
			this.collectionPanelSearchGtkEntry.grab_focus ();
			this.timelineSearchClose.start ();
		}
	},

	onButtonReleaseEvent: function (actor, event, user_data) {
		this.emit ('grab-key-focus');
	},

	collectionPanelSearchEntryClose: function () {
		this.collectionPanelSearchGtkEntry.disconnect (this.notifyTextSignalId);
		this.collectionPanelSearchGtkEntry.text = "";
		this.collectionPanelSearchStack.visible = false;
	},

	load: function () {
		this.collectionLayout.remove_all_children ();
		if (this.insertSignalId) {
			this.collectionlist.disconnect (this.insertSignalId);
		}

		this.loadedSignalId =
		this.collectionlist.connect ('loaded', Lang.bind(this, function () {
			this.collectionlist.disconnect (this.loadedSignalId);
			this.addSignalId =
			this.collectionlist.connect ('add', Lang.bind (this, this.on_collection_add));
			this.addFinishedSignalId =
			this.collectionlist.connect ('add-finished', Lang.bind(this, function () {
				this.collectionlist.disconnect (this.addSignalId);
				this.collectionlist.disconnect (this.addFinishedSignalId);
				this.insertSignalId =
				this.collectionlist.connect ('insert', Lang.bind (this, this.on_collection_insert));
				this.emit ('load-finished');
			}));
			this.collectionlist.request_data ();
		}));
		let createPlaylist = new Create (this.collectionLayout, NamespaceEnum.PLAYLIST);
		createPlaylist.connect('new-playlist', Lang.bind(this, function () {
			this.emit ('new-playlist');
		}));
		createPlaylist.connect('show-message-bar-text', Lang.bind(this, function (create, msg) {
			this.emit ('show-message-bar-text', msg);
		}));
		let createCollection = new Create (this.collectionLayout, NamespaceEnum.COLLECTION);
		createCollection.connect('new-collection', Lang.bind(this, function () {
			this.emit ('new-collection');
		}));
		createCollection.connect('show-message-bar-text', Lang.bind(this, function (create, msg) {
			this.emit ('show-message-bar-text', msg);
		}));
		this.collectionlist.load ();
	}
};

Signals.addSignalMethods(CollectionPanel.prototype);

const ICONSIZE = 48;

function Collection(container, pos, /*IMedialibInfo*/collection_model) {
	this._init(container, pos, /*IMedialibInfo*/collection_model);
}

Collection.prototype = {
	_init: function (container, pos, /*IMedialibInfo*/collection_model) {
		//requires: collection_model of type Playlist or CollectionGroupedByAlbum
		this.collectionStack = new Mx.Stack ({ name: 'collection-background' });
		if (pos == -1)
			container.add_child (this.collectionStack);
		else
			container.insert_child_at_index (this.collectionStack, pos);

		this.albumArt = new AlbumArt.AlbumArt (this.collectionStack,
		                                       150); //albumArtSize
		this.albumArt.defaultAlbumArtArtist.text = collection_model.name;
		this.albumArt.defaultAlbumArtAlbum.text  = "";

		this.collectionIcon = new Mx.Icon ({ x_align: Clutter.ActorAlign.START,
		                                     y_align: Clutter.ActorAlign.END,
		                                     icon_size: ICONSIZE });
		if (collection_model instanceof Octopus.CollectionGroupedByAlbum) this.collectionIcon.style_class = "collection-icon-collection";
		if (collection_model instanceof Octopus.Playlist) this.collectionIcon.style_class = "collection-icon-playlist";
		this.collectionStack.add_child (this.collectionIcon);

		this.collectionOverlay = new Mx.Frame ({ name: 'collection-overlay',
		                                         reactive: true });
		this.collectionStack.add_child (this.collectionOverlay);

		this.collectionMouseOverMenuFrame = new Mx.Frame ({ visible: false });
		this.collectionOverlay.add_child (this.collectionMouseOverMenuFrame);
		this.collectionMouseOverMenu = new CollectionMouseOverMenu (this.collectionMouseOverMenuFrame, collection_model);
		this.collectionMouseOverMenu.connect ('tracklist-panel-show', Lang.bind(this, function () {
			this.emit ('tracklist-panel-show');
		}));

		this.collectionOverlay.connect ('enter-event', Lang.bind(this, function () {
			this.collectionMouseOverMenuFrame.visible = true;
			this.emit ('collection-enter-event');
		}));
		this.collectionOverlay.connect ('leave-event', Lang.bind(this, function () {
			this.collectionMouseOverMenuFrame.visible = false;
			this.emit ('collection-leave-event');
		}));
		this.collectionOverlay.connect('button-release-event', Lang.bind(this, this.onButtonReleaseEvent));
	},

	onButtonReleaseEvent: function (actor, event, user_data) {
		if ((event.get_button () == 1) && (event.get_click_count () == 1)) { //left mouse button
		}
		if ((event.get_button () == 1) && (event.get_click_count () == 2)) { //double click
			this.emit ('tracklist-panel-show');
			return true; //stop
		}
		if ((event.get_button () == 3) && (event.get_click_count () == 1)) { //right mouse button
		}
		return false; //propagate
	}
};

Signals.addSignalMethods(Collection.prototype);

const MENUICONSIZE = 15;

function CollectionMouseOverMenu (container, /*IMedialibInfo*/collection_model) {
	this._init (container, /*IMedialibInfo*/collection_model);
}

CollectionMouseOverMenu.prototype = {
	_init: function (container, /*IMedialibInfo*/collection_model) {
		//mouse-over-menu buttons
		this.collectionMenuLayout = new Mx.BoxLayout ({ style_class: 'collection-menu-layout',
		                                                orientation: Mx.Orientation.HORIZONTAL,
		                                                x_align: Clutter.ActorAlign.END,
		                                                y_align: Clutter.ActorAlign.END });
		container.add_child (this.collectionMenuLayout);
		if (collection_model instanceof Octopus.Playlist) {
			//view
			this.collectionMenuView = new Mx.Button ({ style_class: 'collection-menu-view',
			                                           height: MENUICONSIZE,
			                                           width: MENUICONSIZE });
			this.collectionMenuLayout.add_child (this.collectionMenuView);
			this.collectionMenuView.connect ('clicked', Lang.bind(this, function () {
				this.emit ('tracklist-panel-show');
			}));
			//set active
			this.collectionMenuSetActive = new Mx.Button ({ style_class: 'collection-menu-set-active',
			                                                height: MENUICONSIZE,
			                                                width: MENUICONSIZE });
			this.collectionMenuLayout.add_child (this.collectionMenuSetActive);
			this.collectionMenuSetActive.connect ('clicked', Lang.bind(this, function () {
				collection_model.xmms_playlist_load ();
			}));
			//remove
			this.collectionMenuRemove = new Mx.Button ({ style_class: 'collection-menu-remove',
			                                             height: MENUICONSIZE,
			                                             width: MENUICONSIZE });
			this.collectionMenuLayout.add_child (this.collectionMenuRemove);
			this.collectionMenuRemove.connect ('clicked', Lang.bind(this, function () {
				collection_model.xmms_collection_remove ();
			}));
		}
		if (collection_model instanceof Octopus.CollectionGroupedByAlbum) {
			//view
			this.collectionMenuView = new Mx.Button ({ style_class: 'collection-menu-view',
			                                           height: MENUICONSIZE,
			                                           width: MENUICONSIZE });
			this.collectionMenuLayout.add_child (this.collectionMenuView);
			this.collectionMenuView.connect ('clicked', Lang.bind(this, function () {
				this.emit ('tracklist-panel-show');
			}));
			//edit
			//this.collectionMenuEdit = new Mx.Button ({ style_class: 'collection-menu-edit',
			//                                           height: MENUICONSIZE,
			//                                           width: MENUICONSIZE });
			//this.collectionMenuLayout.add_child (this.collectionMenuEdit);
			//this.collectionMenuEdit.connect ('clicked', Lang.bind(this, function () {
			//	print ("collection edit");
			//}));
			//remove
			this.collectionMenuRemove = new Mx.Button ({ style_class: 'collection-menu-remove',
			                                             height: MENUICONSIZE,
			                                             width: MENUICONSIZE });
			this.collectionMenuLayout.add_child (this.collectionMenuRemove);
			this.collectionMenuRemove.connect ('clicked', Lang.bind(this, function () {
				collection_model.xmms_collection_remove ();
			}));
		}
	}
};

Signals.addSignalMethods(CollectionMouseOverMenu.prototype);

function Create(container, /*NamespaceEnum*/namespace) {
	this._init(container, /*NamespaceEnum*/namespace);
}

Create.prototype = {
	_init: function (container, /*NamespaceEnum*/namespace) {
		this.namespace = namespace;
		this.createStack = new Mx.Stack ({ name: 'create-background' });
		container.add_child (this.createStack);

		this.albumArt = new AlbumArt.AlbumArt (this.createStack,
		                                       150); //albumArtSize

		this.createIcon = new Mx.Icon ({ style_class: 'create-icon',
		                                 x_align: Clutter.ActorAlign.CENTER,
		                                 y_align: Clutter.ActorAlign.CENTER,
		                                 icon_size: ICONSIZE });
		this.createStack.add_child (this.createIcon);

		this.collectionIcon = new Mx.Icon ({ x_align: Clutter.ActorAlign.START,
		                                     y_align: Clutter.ActorAlign.END,
		                                     icon_size: ICONSIZE });
		if (namespace == NamespaceEnum.COLLECTION) this.collectionIcon.style_class = "collection-icon-collection";
		if (namespace == NamespaceEnum.PLAYLIST) this.collectionIcon.style_class = "collection-icon-playlist";
		this.createStack.add_child (this.collectionIcon);

		this.createOverlay = new Mx.Frame ({ name: 'create-overlay',
		                                     reactive: true });
		this.createStack.add_child (this.createOverlay);
		this.createOverlay.connect('button-release-event', Lang.bind(this, this.onButtonReleaseEvent));
		this.createOverlay.connect ('enter-event', Lang.bind(this, function () {
			if (this.namespace == NamespaceEnum.COLLECTION) {
				this.emit ('show-message-bar-text', "new collection");
			}
			if (this.namespace == NamespaceEnum.PLAYLIST) {
				this.emit ('show-message-bar-text', "new playlist");
			}
		}));
		this.createOverlay.connect ('leave-event', Lang.bind(this, function () {
			this.emit ('show-message-bar-text', "");
		}));
	},

	onButtonReleaseEvent: function (actor, event, user_data) {
		if ((event.get_button () == 1) && (event.get_click_count () == 1)) { //left mouse button
		}
		if ((event.get_button () == 1) && (event.get_click_count () == 2)) { //double click
			if (this.namespace == NamespaceEnum.COLLECTION) {
				this.emit ('new-collection');
			}
			if (this.namespace == NamespaceEnum.PLAYLIST) {
				 this.emit ('new-playlist');
			}
			return true; //stop
		}
		if ((event.get_button () == 3) && (event.get_click_count () == 1)) { //right mouse button
		}
		return false; //propagate
	}
};

Signals.addSignalMethods(Create.prototype);
